#pragma once

#include <queue>

#include <pthread.h>

#ifdef __TEST__
template<class T, size_t MAX = 256>
#else
template<class T, size_t MAX = 512>
#endif
class BlockQueue
{
    typedef T value_type;
    typedef BlockQueue<value_type, MAX> self;
public:
    BlockQueue()
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
    }
    BlockQueue(const self&) = delete;
    self& operator=(const self&) = delete;

    value_type pop()
    {
        pthread_mutex_lock(&_mutex);
        while (_q.size() == 0)      //防止线程伪唤醒的情况,线程每次被唤醒的时候都需要进行检测临界区/临界资源的状态
            pthread_cond_wait(&_c_cond, &_mutex);
        value_type out = _q.front();
        _q.pop();
        if (_q.size() < _high)
            pthread_cond_signal(&_p_cond);
            //pthread_cond_broadcast 将该条件变量下所有等待线程唤醒,易造成伪唤醒
        pthread_mutex_unlock(&_mutex);
        return out;
    }

    template<class... Args>
    void emplace(Args&&... args)
    {
        pthread_mutex_lock(&_mutex);
        while (_q.size() == MAX)
            pthread_cond_wait(&_p_cond, &_mutex);
        _q.emplace(args...);
        if (_q.size() > _low)
            pthread_cond_signal(&_c_cond);
        pthread_mutex_unlock(&_mutex);
    }
    void push(const value_type& val)
    {
        emplace(val);
    }
    void push(value_type&& val)
    {
        emplace(std::forward<value_type>(val));
    }

    bool full()
    {
        return _q.size() == MAX;
    }

    bool empty()
    {
        return _q.size() == 0;
    }

    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_p_cond);
        pthread_cond_destroy(&_c_cond);
    }
private:
    std::queue<value_type> _q;   //共享队列
    pthread_mutex_t _mutex;
    pthread_cond_t _c_cond; //消费者队列
    pthread_cond_t _p_cond; //生产者队列
    size_t _high = MAX * 4 / 5;
    size_t _low = MAX / 5;
};
